﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using VIA.DependencyInjection;
using VIA.Infrastructure;
using VIA.Integration.Domain;
using VIA.RbacPassport;
using VIA.SiMoJi.Domain.Option;
using static VT.Framework.Utils.UtilMiniDump;
using Timer = System.Timers.Timer;

namespace VIA.SiMoJi.Domain
{
    internal class AutoLogoutServiceEventHandle : IEventHandle<UserLoginEvent>, IEventHandle<UserLogoutEvent>
    {
        ILogger _userChangLogger;
        CustomAutoLogoutService _service;
        public AutoLogoutServiceEventHandle(ILoggerFactory loggerFactory, CustomAutoLogoutService service)
        {
            _service = service;
            _userChangLogger = loggerFactory.CreateLogger("User");
        }
        public Task Handle(UserLoginEvent notification, CancellationToken cancellationToken)
        {
            _service.OnUserLogin(notification.User);
            _userChangLogger.LogInformation($"用户登录：{notification.User.Account}");
            return Task.CompletedTask;
        }

        public Task Handle(UserLogoutEvent notification, CancellationToken cancellationToken)
        {
            _userChangLogger.LogInformation($"用户登出：{notification.User.Account}");
            return Task.CompletedTask;
        }
    }
    internal class CustomAutoLogoutService : ISingletonDependency
    {
        ILoginService _loginService;
        IRoleManager _roleManager;
        IServiceProvider _service;
        Timer _autoLogoutTimer;
        public CustomAutoLogoutService(IServiceProvider service)
        {
            _service = service.GetService<IServiceProvider>();
            _loginService = service.GetService<ILoginService>();
            _roleManager = service.GetService<IRoleManager>();
        }
        double totalMilliseconds = 60 * 1000;
        public async void OnUserLogin(User user)
        {
            var optionRepository = _service.GetService<IOptionRepository>();
            var option = optionRepository.Get<InspectorOption>();
            if (user != User.Anonymous)
            {
                var roles = await _roleManager.GetUserRolesAsync(user.Id);
                if (roles.Any(x => x.Name.Contains("管理员")))
                {
                    totalMilliseconds = option.AutoLogoutOption.ManagerTime * 60 * 1000;
                }
                else if (roles.Any(x => x.Name.Contains("工程师")))
                {
                    totalMilliseconds = option.AutoLogoutOption.EngineerTime * 60 * 1000;
                }
                else if (roles.Any(x => x.Name.Contains("操作员")))
                {
                    totalMilliseconds = option.AutoLogoutOption.OPNTime * 60 * 1000;
                }
                AutoLogout(totalMilliseconds);
            }
        }

        void AutoLogout(double totalMilliseconds)
        {
            if (_autoLogoutTimer != null)
            {
                _autoLogoutTimer.Stop();
                _autoLogoutTimer.Dispose();
            }
            _autoLogoutTimer = new Timer(totalMilliseconds);
            _autoLogoutTimer.Interval = 100;
            _autoLogoutTimer.Elapsed += AutoLogoutTimerNotOperation_Elapsed;
            _autoLogoutTimer.Start();
        }

        private async void AutoLogoutTimerNotOperation_Elapsed(object sender, ElapsedEventArgs e)
        {
            long elapsedTime = User32API.GetLastInputTime();
            if (elapsedTime > totalMilliseconds)
            {
                _autoLogoutTimer.Stop();
                _autoLogoutTimer.Dispose();
                _autoLogoutTimer = null;
                await _loginService.LogoutAsync();
            }
        }
    }
    /// <summary>
    /// User32API
    /// </summary>
    internal static class User32API
    {
        [StructLayout(LayoutKind.Sequential)]
        struct LASTINPUTINFO
        {
            [MarshalAs(UnmanagedType.U4)]
            public int cbSize;
            [MarshalAs(UnmanagedType.U4)]
            public uint dwTime;
        }

        [DllImport("user32.dll")]
        static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

        /// <summary>
        /// 获取最后无操作时间
        /// </summary>
        /// <returns>间隔时间单位:毫秒秒</returns>
        public static long GetLastInputTime()
        {
            LASTINPUTINFO lastInputInfo = new LASTINPUTINFO();
            lastInputInfo.cbSize = Marshal.SizeOf(lastInputInfo);
            if (!GetLastInputInfo(ref lastInputInfo))
            {
                return 0;
            }
            return (Environment.TickCount - lastInputInfo.dwTime);
        }
    }
}
